(function() { var $injector = angular.injector(['ng']); $injector.invoke(function($http, $rootScope) { $rootScope.$apply(function() { $http.post('/rest/user/login', { }).then(function successCallback(res) { angular.module("app").constant("USER", res.data.user); angular.bootstrap(document, ['app']); }); }); }); })(); var app = angular.module('app', ['ui.bootstrap', 'amChartsDirective', 'ngRoute', 'pascalprecht.translate']); app.filter('html', ['$sce', function($sce) { return function(text) { return $sce.trustAsHtml(text); }; }]); app.filter('useFilter', function($filter) { return function() { if (typeof arguments[0] == 'undefined') { return ''; }; var filterName = [].splice.call(arguments, 1, 1)[0]; return $filter(filterName).apply(null, arguments); }; }) app.filter('useFilter2', function($filter) { return function() { if (typeof arguments[0] == 'undefined') { return '--'; }; var filterName = [].splice.call(arguments, 1, 1)[0]; return $filter(filterName).apply(null, arguments); }; }) app.filter('exists', function($filter) { return function(v) { if (v === 0 || v == '0.00') { return '--'; } if (!v) { return ''; }; return v; }; }) app.filter('secondsToHHmmss', function($filter) { return function(seconds) { if (seconds) { return $filter('date')(new Date(0, 0, 0).setSeconds(seconds), 'HH:mm:ss'); } return '00:00:00'; }; }) app.filter('mcdate', function($filter) { return function(datum) { var d = new Date(datum); return d.getDate() + '/' + (d.getMonth() + 1) + '/' + d.getFullYear() + ' - ' + d.getHours() + ':' + d.getMinutes(); }; }) app.filter('minzero', function($filter) { return function(int) { return (int < 0) ? 0 : int; }; }) app.filter('path', function() { return function(url) { return url = url.substring(url.indexOf("/")); }; }) app.filter('truefalse', function() { return function(b) { return (b) ? 'Yes' : 'No'; }; }) app.filter('string', function() { return function(b) { return b; }; }) app.filter('objToArray', function() { return function(input, attribute) { if (!angular.isObject(input)) return input; var array = []; for (var objectKey in input) { array.push(input[objectKey]); } return array; } }) app.factory('h', function($rootScope, $http) { return { siteId: function() { if ($rootScope.user.site) { if ($rootScope.user.site._id) { return $rootScope.user.site._id.$oid; } } }, login: function(cb) { $http.post('/rest/user/login', { }).then(function successCallback(res) { $rootScope.user = res.data.user; cb(); }); }, colors: function() { return angular.extend([], ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000'], $rootScope.user.reseller.config.chartcolors) }, metrics: function(key) { var allMetrics = { analytics: { sessions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, users: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, pageviews: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, pageviewsPerSession: { typefilter: 'number', filtercomparator: 2, 'datemerge': 'avg' }, avgSessionDuration: { typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' }, percentNewSessions: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, bounceRate: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg', 'reversesign': true }, goalCompletionsAll: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, goalValueAll: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, goalConversionRateAll: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, goalAbandonRateAll: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, uniquePageviews: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, avgTimeOnPage: { typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' }, entrances: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, exitRate: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, pageValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, exits: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, ROAS: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' }, costPerTransaction: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' }, totalValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, adCost: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, CPC: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' }, adClicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, transactions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, uniquePurchases: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, totalValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, revenuePerTransaction: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' }, itemQuantity: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, itemsPerPurchase: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' }, }, copernica: { Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 }, subject: { name: 'Subject', typefilter: 'number', filtercomparator: 0 }, type: { name: 'Type', typefilter: 'string' }, destinations: { name: 'Destinations', typefilter: 'number', filtercomparator: 0 }, abuses: { name: 'Abuses', typefilter: 'number', filtercomparator: 0 }, clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0 }, uniqueclicks: { name: 'Unique Clicks', typefilter: 'number', filtercomparator: 0 }, deliveries: { name: 'Deliveries', typefilter: 'number', filtercomparator: 0 }, errors: { name: 'Errors', typefilter: 'number', filtercomparator: 0 }, impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0 }, uniqueimpressions: { name: 'Unique Impressions', typefilter: 'number', filtercomparator: 0 }, retries: { name: 'Retries', typefilter: 'number', filtercomparator: 0 }, unsubscribes: { name: 'Unsubscribes', typefilter: 'number', filtercomparator: 0 }, }, facebookads: { clicks: { name: 'Klikken', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, impressions: { name: 'Impressies', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, cpc: { name: 'cpc', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' }, cpm: { name: 'cpm', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' }, ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' }, Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' }, CostPerConversion: { name: 'spend / conversie', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'avg' }, ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' }, ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' }, relevance_score: { name: 'Relevantie Score', typefilter: 'number', filtercomparator: 0, hide: { 'panel': true }, 'datemerge': 'avg' }, spend: { name: 'Kosten', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'sum' }, }, facebookinsights: { fans: { name: 'Fans', typefilter: 'number', filtercomparator: 0 }, interacties: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 }, bereik: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, }, googlexads: { Clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, Impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, Date: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, AverageCpc: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' }, Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'sum' }, CostPerConversion: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' }, ConversionRate: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, AbsoluteTopImpressionPercentage: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' }, ConversionValue: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' }, SearchImpressionShare: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' }, SearchAbsoluteTopImpressionShare: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' }, roas: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' }, }, instagram: { impressions: { name: 'Fans', typefilter: 'number', filtercomparator: 0 }, reach: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 }, follower_count: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, profile_views: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, website_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, email_contacts: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, get_directions_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, phone_call_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, text_message_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 }, }, linkedin: { Placeholder: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, shareCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, likeCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, engagement: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, clickCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, impressionCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, commentCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, }, linkedinxads: { impressions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, clicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, oneClickLeads: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, externalWebsiteConversions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, }, mailchimp: { Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 }, member_count: { name: 'Aanmeldingen', typefilter: 'number', filtercomparator: 0 }, list_rating: { name: 'Rating', typefilter: 'number', filtercomparator: 0 }, click_rate: { name: 'Klik Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' }, open_rate: { name: 'Open Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' }, emails_sent: { name: 'Email verstuurd', typefilter: 'number', filtercomparator: 0 }, send_time: { name: 'Verstuurd op', typefilter: 'mcdate', filtercomparator: 0 }, unsubscribed: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 }, unsubscribe_count: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 }, cleaned_count: { name: 'Verwijderd', typefilter: 'number', filtercomparator: 0 }, bounces: { name: 'Bounce', typefilter: 'number', filtercomparator: 0 }, total_orders: { name: 'Orders', typefilter: 'number', filtercomparator: 0 }, recipient_clicks: { name: 'klikken', typefilter: 'number', filtercomparator: 0 }, total_revenue: { name: 'Totale opbrangest', typefilter: 'number', filtercomparator: 0, 'after': '€' }, }, mybusiness: { Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 }, QUERIES_DIRECT: { name: 'Directe zoekopdrachten', typefilter: 'number', filtercomparator: 0 }, QUERIES_INDIRECT: { name: 'Indirecte zoekopdrachten', typefilter: 'number', filtercomparator: 0 }, VIEWS_MAPS: { name: 'Google maps', typefilter: 'number', filtercomparator: 0 }, VIEWS_SEARCH: { name: 'Google zoeken', typefilter: 'number', filtercomparator: 0 }, QUERIES_DIRECT: { name: 'Bedrijf zoekopdacht', typefilter: 'number', filtercomparator: 0 }, QUERIES_INDIRECT: { name: 'Categorie zoekopdracht', typefilter: 'number', filtercomparator: 0 }, PHOTOS_VIEWS_MERCHANT: { name: 'Van eigenaars', typefilter: 'number', filtercomparator: 0 }, PHOTOS_VIEWS_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 }, PHOTOS_COUNT_MERCHANT: { name: 'Van eigenaar', typefilter: 'number', filtercomparator: 0 }, PHOTOS_COUNT_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 }, Date: { name: 'Datum', typefilter: 'number', filtercomparator: 0 }, AverageCpc: { name: 'Gemiddelde kosten per klik', typefilter: 'number', filtercomparator: 2, 'before': '€' }, Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%' }, Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0 }, Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€' }, CostPerConversion: { name: 'Kosten per conversie', typefilter: 'number', filtercomparator: 0, 'before': '€' }, ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' }, AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 1 }, ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€' }, }, searchconsole: { clicks: { typefilter: 'number', filtercomparator: 0, 'reverse': true, 'datemerge': 'sum' }, ctr: { typefilter: 'number', filtercomparator: 2, 'after': '%', 'reverse': true, 'datemerge': 'avg' }, impressions: { typefilter: 'number', filtercomparator: 0, 'reverse': true, 'datemerge': 'sum' }, Date: { typefilter: 'number', filtercomparator: 0 }, position: { typefilter: 'number', filtercomparator: 1, 'reverse': false, 'reversesign': true, 'datemerge': 'avg' }, }, youtube: { commentCount: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, subscriberCount: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, videoCount: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, viewCount: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' }, views: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, shares: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, likes: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, dislikes: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, comments: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, subscribersGained: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, subscribersLost: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' }, estimatedMinutesWatched: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 1, 'datemerge': 'sum' }, annotationCloseRate: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' }, annotationClickThroughRate: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' }, averageViewDuration: { name: 'ROAS', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' }, } } return allMetrics[key]; } } }); app.directive('bullet', function($compile) { return { restrict: 'E', scope: { type: '=' }, template: '', }; }); app.directive("clientscript", function() { var updateScripts = function(element) { return function(script) { element.empty(); var scriptTag = angular.element(document.createElement("script")); scriptTag.text(script) element.append(scriptTag); }; }; return { restrict: "EA", scope: { scripts: "=" }, link: function(scope, element) { scope.$watch("scripts", updateScripts(element)); } }; }) app.filter('maxserp', function() { return function(text, length, end) { if (text == 100 || text === undefined) { return '--'; } return text; } }) app.directive('change', function() { return { restrict: 'E', replace: true, scope: { type: '@' }, template: '{{change}} ', link: function(scope) { scope.$watch('type', function() { if (scope.type == '0') { scope.change = '--'; } else if (scope.type < 1) { scope.change = scope.type + ' '; scope.class = 'fa fa-long-arrow-down text-warning'; } else { scope.change = scope.type + ' '; scope.class = 'fa fa-long-arrow-up text-success'; } }); } }; }); app.directive('infiniteScroll', [ '$rootScope', '$window', '$timeout', function($rootScope, $window, $timeout) { return { link: function(scope, elem, attrs) { var checkWhenEnabled, handler, scrollDistance, scrollEnabled; $window = angular.element($window); scrollDistance = 0; if (attrs.infiniteScrollDistance != null) { scope.$watch(attrs.infiniteScrollDistance, function(value) { return scrollDistance = parseInt(value, 10); }); } scrollEnabled = true; checkWhenEnabled = false; if (attrs.infiniteScrollDisabled != null) { scope.$watch(attrs.infiniteScrollDisabled, function(value) { scrollEnabled = !value; if (scrollEnabled && checkWhenEnabled) { checkWhenEnabled = false; return handler(); } }); } handler = function() { var elementBottom, remaining, shouldScroll, windowBottom; windowBottom = $window.height() + $window.scrollTop(); elementBottom = elem.offset().top + elem.height(); remaining = elementBottom - windowBottom; shouldScroll = remaining <= $window.height() * scrollDistance; if (shouldScroll && scrollEnabled) { if ($rootScope.$$phase) { return scope.$eval(attrs.infiniteScroll); } else { return scope.$apply(attrs.infiniteScroll); } } else if (shouldScroll) { return checkWhenEnabled = true; } }; $window.on('scroll', handler); scope.$on('$destroy', function() { return $window.off('scroll', handler); }); return $timeout((function() { if (attrs.infiniteScrollImmediateCheck) { if (scope.$eval(attrs.infiniteScrollImmediateCheck)) { return handler(); } } else { return handler(); } }), 0); } }; } ]) app.filter('cleanurl', function() { return function(url) { return url.replace(/(^\w+:|^)\/\//, ''); }; }); app.filter('mstotime', function() { return function(bytes) { return (bytes > 1000) ? Math.round(bytes / 10) / 100 + 's' : Math.round(bytes) + 'ms'; }; }); app.filter('filename', function() { return function(url) { url = url.split(/[?#]/)[0].replace(/\/$/, ""); return url.substring(url.lastIndexOf('/') + 1) }; }); app.directive('ngGauge', gaugeMeterDirective) .provider('ngGauge', gaugeMeterProviderFn); gaugeMeterProviderFn.$inject = []; function gaugeMeterProviderFn() { var defaultOptions = { size: 200, value: undefined, min: 0, max: 100, cap: 'butt', thick: 6, type: 'full', foregroundColor: 'rgba(0, 150, 136, 1)', backgroundColor: 'rgba(0, 0, 0, 0.1)', duration: 1500, fractionSize: null, labelOnly: false, }; this.setOptions = function(customOptions) { if (!(customOptions && angular.isObject(customOptions))) throw new Error('Invalid option type specified in the ngGaugeProvider'); defaultOptions = angular.merge(defaultOptions, customOptions); }; var ngGauge = { getOptions: function() { return angular.extend({}, defaultOptions); } }; this.$get = function() { return ngGauge; }; } gaugeMeterDirective.$inject = ['ngGauge']; function gaugeMeterDirective(ngGauge) { var tpl = '
' + '{{prepend}}' + '{{value | number}}' + '{{value | number: fractionSize}}' + '{{append}}' + '{{ label }}' + '
'; var Gauge = function(element, options) { this.element = element.find('canvas')[0]; this.text = element.find('span'); this.legend = element.find('b'); this.unit = element.find('u'); this.context = this.element.getContext('2d'); this.options = options; this.init(); }; Gauge.prototype = { init: function() { this.setupStyles(); this.create(null, null); }, setupStyles: function() { this.context.canvas.width = this.options.size; this.context.canvas.height = this.options.size; this.context.lineCap = this.options.cap; this.context.lineWidth = this.options.thick; var lfs = this.options.size * 0.30, llh = this.options.size; this.text.css({ display: 'inline-block', fontWeight: 'normal', width: '100%', position: 'absolute', textAlign: 'center', overflow: 'hidden', textOverflow: 'ellipsis', fontSize: lfs + 'px', lineHeight: llh + 'px' }); this.unit.css({ textDecoration: 'none', fontSize: '0.6em', fontWeight: 200, opacity: 0.8 }); var fs = this.options.labelOnly ? lfs * 0.8 : this.options.size / 13; var lh = this.options.labelOnly ? llh : (5 * fs) + parseInt(this.options.size); this.legend.css({ display: 'inline-block', width: '100%', position: 'absolute', textAlign: 'center', overflow: 'hidden', textOverflow: 'ellipsis', fontWeight: 'normal', fontSize: fs + 'px', lineHeight: lh + 'px' }); }, create: function(nv, ov) { var self = this, type = this.getType(), bounds = this.getBounds(type), duration = this.getDuration(), min = this.getMin(), max = this.getMax(), value = this.clamp(this.getValue(), min, max), start = bounds.head, unit = (bounds.tail - bounds.head) / (max - min), displacement = unit * (value - min), tail = bounds.tail, color = this.getForegroundColorByRange(value), requestID, startTime; if (nv && ov) { displacement = unit * nv - unit * ov; } function animate(timestamp) { timestamp = timestamp || new Date().getTime(); var runtime = timestamp - startTime; var progress = Math.min(runtime / duration, 1); // never exceed 100% var previousProgress = ov ? (ov * unit) : 0; var middle = start + previousProgress + displacement * progress; self.drawShell(start, middle, tail, color); if (runtime < duration) { requestID = window.requestAnimationFrame(function(timestamp) { animate(timestamp); }); } else { cancelAnimationFrame(requestID); } } requestAnimationFrame(function(timestamp) { startTime = timestamp || new Date().getTime(); animate(timestamp); }); }, getBounds: function(type) { var head, tail; if (type == 'semi') { head = Math.PI; tail = 2 * Math.PI; } else if (type == 'full') { head = 1.5 * Math.PI; tail = 3.5 * Math.PI; } else if (type === 'arch') { head = 0.8 * Math.PI; tail = 2.2 * Math.PI; } return { head: head, tail: tail }; }, drawShell: function(start, middle, tail, color) { var context = this.context, center = this.getCenter(), radius = this.getRadius(), foregroundColor = color, backgroundColor = this.getBackgroundColor(); this.clear(); middle = Math.max(middle, start); // never below 0% middle = Math.min(middle, tail); // never exceed 100% context.beginPath(); context.strokeStyle = backgroundColor; context.arc(center.x, center.y, radius, middle, tail, false); context.stroke(); context.beginPath(); context.strokeStyle = foregroundColor; context.arc(center.x, center.y, radius, start, middle, false); context.stroke(); }, clear: function() { this.context.clearRect(0, 0, this.getWidth(), this.getHeight()); }, update: function(nv, ov) { this.create(nv, ov); }, destroy: function() { this.clear(); }, getRadius: function() { var center = this.getCenter(); return center.x - this.getThickness(); }, getCenter: function() { var x = this.getWidth() / 2, y = this.getHeight() / 2; return { x: x, y: y }; }, getValue: function() { return this.options.value; }, getMin: function() { return this.options.min; }, getMax: function() { return this.options.max; }, getWidth: function() { return this.context.canvas.width; }, getHeight: function() { return this.context.canvas.height; }, getThickness: function() { return this.options.thick; }, getBackgroundColor: function() { return this.options.backgroundColor; }, getForegroundColor: function() { return this.options.foregroundColor; }, getForegroundColorByRange: function(value) { var isNumber = function(value) { return value != undefined && !isNaN(parseFloat(value)) && !isNaN(Number(value)); }; var match = Object.keys(this.options.thresholds) .filter(function(item) { return isNumber(item) && Number(item) <= value; }) .sort(function(a, b) { return Number(a) > Number(b); }).reverse()[0]; return match !== undefined ? this.options.thresholds[match].color || this.getForegroundColor() : this.getForegroundColor(); }, getLineCap: function() { return this.options.cap; }, getType: function() { return this.options.type; }, getDuration: function() { return this.options.duration; }, clamp: function(value, min, max) { return Math.max(min, Math.min(max, value)); } }; return { restrict: 'E', replace: true, template: tpl, scope: { append: '@?', backgroundColor: '@?', cap: '@?', foregroundColor: '@?', label: '@?', labelOnly: '@?', prepend: '@?', size: '@?', thick: '@?', type: '@?', duration: '@?', value: '=?', min: '=?', max: '=?', thresholds: '=?', fractionSize: '=?' }, link: function(scope, element) { var defaults = ngGauge.getOptions(); // fetching default settings from provider scope.min = angular.isDefined(scope.min) ? scope.min : defaults.min; scope.max = angular.isDefined(scope.max) ? scope.max : defaults.max; scope.value = angular.isDefined(scope.value) ? scope.value : defaults.value; scope.size = angular.isDefined(scope.size) ? scope.size : defaults.size; scope.cap = angular.isDefined(scope.cap) ? scope.cap : defaults.cap; scope.thick = angular.isDefined(scope.thick) ? scope.thick : defaults.thick; scope.type = angular.isDefined(scope.type) ? scope.type : defaults.type; scope.duration = angular.isDefined(scope.duration) ? scope.duration : defaults.duration; scope.labelOnly = angular.isDefined(scope.labelOnly) ? scope.labelOnly : defaults.labelOnly; scope.foregroundColor = angular.isDefined(scope.foregroundColor) ? scope.foregroundColor : defaults.foregroundColor; scope.backgroundColor = angular.isDefined(scope.backgroundColor) ? scope.backgroundColor : defaults.backgroundColor; scope.thresholds = angular.isDefined(scope.thresholds) ? scope.thresholds : {}; scope.fractionSize = angular.isDefined(scope.fractionSize) ? scope.fractionSize : defaults.fractionSize; var gauge = new Gauge(element, scope); scope.$watch('value', watchData, false); scope.$watch('min', watchData, false); scope.$watch('max', watchData, false); scope.$watch('cap', watchOther, false); scope.$watch('thick', watchOther, false); scope.$watch('type', watchOther, false); scope.$watch('size', watchOther, false); scope.$watch('duration', watchOther, false); scope.$watch('foregroundColor', watchOther, false); scope.$watch('backgroundColor', watchOther, false); scope.$watch('thresholds', watchOther, false); scope.$watch('fractionSize', watchData, false); scope.$on('$destroy', function() {}); scope.$on('$resize', function() {}); function watchData(nv, ov) { if (!gauge) return; if (!angular.isDefined(nv) || angular.equals(nv, ov)) return; gauge.update(nv, ov); } function watchOther(nv, ov) { if (!angular.isDefined(nv) || angular.equals(nv, ov)) return; gauge.destroy(); gauge.init(); } } }; } app.config(['$routeProvider', '$locationProvider', 'USER', '$sceProvider', '$translateProvider', function AppConfig($routeProvider, $locationProvider, USER, $sceProvider, $translateProvider) { angular.lowercase = angular.$$lowercase; $translateProvider.useStaticFilesLoader({ prefix: '/translations/', suffix: '.json?r=' + Math.random() }); /* ZET */ $translateProvider.preferredLanguage(USER.site.locale.lang); $translateProvider.useSanitizeValueStrategy('sce'); $sceProvider.enabled(false); $routeProvider .when('/', { title: 'APP', templateUrl: 'view/home/index.html?r=' + r, nav: 'dashboard' }) /* help*/ .when('/help', { title: 'Help', templateUrl: 'view/help/index.html?r=' + r, nav: 'help' }) /* onpage seo*/ .when('/onpage-seo', { title: 'ONPAGE', templateUrl: 'view/onpage/index.status.html?r=' + r, nav: 'onpage' }) .when('/onpage-seo/scan/:pageid', { title: 'ONPAGE SCAN', templateUrl: 'view/onpage/scan.html?r=' + r, nav: 'onpage', controller: function($scope, $routeParams) { $scope.pageid = $routeParams.pageid; }, }) .when('/onpage-seo/:viewrulelabel', { title: 'ONPAGE', templateUrl: 'view/onpage/index.status.html?r=' + r, nav: 'onpage', controller: function($scope, $routeParams) { $scope.viewrulelabel = $routeParams.viewrulelabel; }, }) .when('/onpage-seo/:viewrulelabel/:viewrule', { title: 'ONPAGE', templateUrl: 'view/onpage/index.status.html?r=' + r, nav: 'onpage', controller: function($scope, $routeParams) { $scope.viewrulelabel = $routeParams.viewrulelabel; $scope.viewrule = $routeParams.viewrule; }, }) /* linkbuilding*/ .when('/content/', { title: 'Content Intelligence', templateUrl: 'view/content/index.html?r=' + r, nav: 'content' }) .when('/content/:modelid', { title: 'Content Intelligence', templateUrl: 'view/content/model.html?r=' + r, nav: 'content', controller: function($scope, $routeParams) { $scope.modelid = $routeParams.modelid; }, }) /* linkbuilding*/ .when('/linkbuilding/assistant', { title: 'Linkbuilding', templateUrl: 'view/linkbuilding/assistant.html?r=' + r, nav: 'linkbuilding' }) .when('/linkbuilding/template', { title: 'Linkbuilding', templateUrl: 'view/linkbuilding/template.html?r=' + r, nav: 'linkbuilding' }) .when('/linkbuilding/wizzard', { title: 'Linkbuilding', templateUrl: 'view/linkbuilding/wizzard.html?r=' + r, nav: 'linkbuilding' }) .when('/linkbuilding/manager', { title: 'Linkbuilding', templateUrl: 'view/linkbuilding/manager.html?r=' + r, nav: 'linkbuilding' }) /* reports*/ .when('/analytics/:report/:view', { title: 'SITES', templateUrl: 'view/api/analytics.html?r=' + r, nav: 'analytics', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/analytics4/:report/:view', { title: 'SITES', templateUrl: 'view/api/analytics4.html?r=' + r, nav: 'analytics4', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/searchconsole/:report/:view', { title: 'SEARCHCONSOLE', templateUrl: 'view/api/searchconsole.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/youtube/:report/:view', { title: 'youtube', templateUrl: 'view/api/youtube.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/searchconsole/:report/:view/:filter', { title: 'SEARCHCONSOLE', templateUrl: 'view/api/searchconsole.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; $scope.urlfilter = $routeParams.filter; }, }) .when('/mailchimp/:report/:view', { title: 'mailchimp', templateUrl: 'view/api/mailchimp.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/mailchimp/:report/:view/:filter', { title: 'mailchimp', templateUrl: 'view/api/mailchimp.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; $scope.urlfilter = $routeParams.filter; }, }) .when('/copernica/:report/:view', { title: 'copernica', templateUrl: 'view/api/copernica.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/copernica/:report/:view/:filter', { title: 'copernica', templateUrl: 'view/api/copernica.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; $scope.urlfilter = $routeParams.filter; }, }) .when('/facebookads/:report/:view', { title: 'facebookads', templateUrl: 'view/api/facebookxads.html?r=' + r, nav: 'ads', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/facebookinsights/:report/:view', { title: 'facebookinsights', templateUrl: 'view/api/facebookinsights.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/instagram/:report/:view', { title: 'instagram', templateUrl: 'view/api/instagram.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/linkedin/:report/:view', { title: 'linkedin', templateUrl: 'view/api/linkedin.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/linkedinxads/:report/:view', { title: 'linkedinxads', templateUrl: 'view/api/linkedinxads.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/googleads/:report/:view', { title: 'googleads', templateUrl: 'view/api/googlexads.html?r=' + r, nav: 'ads', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/mybusiness/:report/:view', { title: 'MYBUSINESS', templateUrl: 'view/api/mybusiness.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; $scope.urlview = $routeParams.view; }, }) .when('/planning', { title: 'planning', templateUrl: 'view/planning/index.html?r=' + r, nav: 'planning', }) .when('/site', { title: 'SITES', templateUrl: 'view/site/index.html?r=' + r, nav: 'sites', }) .when('/site/upgrade/:orderstate', { title: 'SITES', templateUrl: 'view/site/upgrade.html?r=' + r, nav: 'sites', controller: function($scope, $routeParams) { $scope.orderstate = $routeParams.orderstate; }, allowguest: true }) .when('/site/upgrade', { title: 'SITES', templateUrl: 'view/site/upgrade.html?r=' + r, nav: 'sites', allowguest: true }) .when('/sites', { title: 'SITES', templateUrl: 'view/sites/index.html?r=' + r, nav: 'sites', }) .when('/sites/new', { title: 'Add a new site', templateUrl: 'view/sites/first.html?r=' + r, nav: 'sites', }) .when('/rank-tracker', { title: 'Rank Tracker', templateUrl: 'view/rank-tracker/index.html?r=' + r, nav: 'ranktracker', }) .when('/rank-tracker/competitors', { title: 'Rank Tracker - Competitors', templateUrl: 'view/rank-tracker/competitors.html?r=' + r, nav: 'ranktracker', }) .when('/rank-tracker/insights', { title: 'Rank Tracker - Insights', templateUrl: 'view/rank-tracker/insights.html?r=' + r, nav: 'ranktracker', }) .when('/keywordtool', { title: 'Rank Tracker', templateUrl: 'view/keywordtool/index.html?r=' + r, nav: 'keywordtool', }) .when('/insights', { title: 'Insights', templateUrl: 'view/insights/index.html?r=' + r, nav: 'insights', }) .when('/insights/:report', { title: 'Insights', templateUrl: 'view/insights/index.html?r=' + r, nav: 'tools', controller: function($scope, $routeParams) { $scope.urlreport = $routeParams.report; }, }) /*report*/ .when('/report', { title: 'Report', templateUrl: 'view/report/index.html?r=' + r, nav: 'report', }) .when('/report/:report_id', { title: 'Report', templateUrl: 'view/report/report.html?r=' + r, nav: 'report', controller: function($scope, $routeParams) { $scope.report_id = $routeParams.report_id; }, }) .when('/reportpage/:key', { title: 'Report', templateUrl: 'view/report/page.html?r=' + r, nav: 'report', controller: function($scope, $routeParams) { $scope.key = $routeParams.key; }, }) /* guest*/ .when('/sites/first', { title: 'Add your first site', templateUrl: 'view/sites/first.html?r=' + r, nav: 'sites', allowguest: true, }) .when('/user/login', { title: 'LOGIN', allowguest: true, nav: 'user', class: 'fullscreen', templateUrl: 'view/user/login.html?r=' + r, }) .when('/user', { title: 'USER', nav: 'user', templateUrl: 'view/user/index.html?r=' + r, }) .when('/user/register', { title: 'LOGIN', nav: 'user', class: 'fullscreen', templateUrl: 'view/user/register.html?r=' + r, allowguest: true, }) .when('/user/recover', { title: 'RECOVER PASSWORD', templateUrl: 'view/user/recover.html?r=' + r, nav: 'user', class: 'fullscreen', allowguest: true, }) .when('/settings/reseller', { title: 'RESELLER', templateUrl: 'view/reseller/index.html?r=' + r, nav: 'user', allowguest: true, }) .when('/settings/site', { title: 'RESELLER', templateUrl: 'view/site/index.html?r=' + r, nav: 'user', allowguest: false, }) .otherwise({ redirectTo: '/' }); // enable html5Mode for pushstate ('#'-less URLs) $locationProvider.html5Mode(true); }]); app.run(['$route', '$rootScope', '$location', '$window', 'USER', function($route, $rootScope, $location, $window, USER) { $rootScope.r = r; $rootScope.user = USER; //set menu state $rootScope.app = { body: { class: ['md-open', 'closed'] } }; $rootScope.$on('$routeChangeSuccess', function(event, current, prev) { $rootScope.app = { body: { class: ['md-open', 'closed'] } }; $rootScope.modal = {}; if (!$rootScope.user._id && !$route.current.allowguest) { $location.path('/user/login'); } else if (!$rootScope.user.site._id && !$route.current.allowguest) { $location.path('/sites/first'); } else if (!$route.current.allowguest && $rootScope.user.site._id && current.originalPath != '/site/upgrade' && $rootScope.user.site.status.expire - (Date.now() / 1000) < 0) { //if ($rootScope.user.reseller.config.own) { $location.path('/site/upgrade'); //} } $window.gtag('config', 'UA-44422450-8', { 'page_path': $location.path() }); $window.gtag('event', 'page_view'); $rootScope.app.meta = { nav: $route.current.nav, class: $route.current.class, title: USER.reseller.config.name + ' - ' + $route.current.title, description: $route.current.description }; $rootScope.app.sitesdropdown = false; }); }]) app.controller('core', ['$scope', '$rootScope', '$location', 'h', '$templateRequest', '$window', '$http', '$route', '$translate', '$http', function($scope, $rootScope, $location, h, $templateRequest, $window, $http, $route, $translate, $http) { $scope.fnToggleMenu = function() { $rootScope.app.body.class = ($rootScope.app.body.class[0] == 'md-open') ? ['md-closed', 'open'] : ['md-open', 'closed']; } $scope.fnLogout = function() { $http.post('/rest/user/logout').then(function successCallback(res) { h.login(function() { $location.path('/user/login'); }); }); } $scope.fnModal = function(url) { $rootScope.modal = {}; $rootScope.modal.show = true; $rootScope.modal.url = 'view/' + url + '.html'; } $scope.fnCloseModal = function() { $rootScope.modal = {}; } $scope.fnClick = function(path) { $location.path(path); } $scope.fnGoto = function(path) { //$location.path(path); $window.location.href = path; } $scope.fnSetLang = function(lang) { $rootScope.user.site.locale.lang = lang; $translate.use(lang); $http.get('/rest/global/lang.set', { params: { 'lang': lang, } }); } $scope.fnChangeSite = function(site) { $http.post('/rest/sites/change', { websiteid: site._id.$oid }).then(function successCallback(res) { h.login(function() { $rootScope._pages = false; $rootScope._history = false; if ($location.path() == '/site/upgrade') { $scope.fnClick('/'); } $route.reload(); }); }); } $scope.fnSitesDropdown = function(site) { $rootScope.app.sitesdropdown = !$rootScope.app.sitesdropdown; } $scope.fnDaysLeft = function() { return Math.ceil(($rootScope.user.site.status.expire - (Date.now() / 1000)) / (24 * 60 * 60)); } $scope.isValidSite = function() { return ($rootScope.user.site.status.expire > (Date.now() / 1000)) ? true : false; } $scope.colors = ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000'] $scope.fnPdf = function() { console.log('asdasdasd'); var imgs = document.getElementsByTagName('canvas'); for (var i in imgs) { if (typeof(imgs[i]) == 'object') { var img = imgs[i].toDataURL("image/png"); var replace = document.createElement("img"); replace.src = img; imgs[i].parentNode.replaceChild(replace, imgs[i]); } } $http.post("/rest/report/page.download", { html: angular.element('.reportcontainer').html() }).then(function successCallback(res) { $scope.fnGoto('https://pdfssl1.seoserver.nl/engels/page.php?website_id=' + h.siteId() + '&reseller_id=' + $scope.user.reseller._id.$oid + '&key=' + res.data.k) /*$http.get('https://pdfssl1.seoserver.nl/engels/page.php', { 'params': { 'website_id': h.siteId(), 'reseller_id': $scope.user.reseller._id.$oid, 'key': res.data.k } }).then(function successCallback(pdf) { var newBlob = new Blob([pdf.data], { type: "application/pdf" }) console.log(newBlob); });*/ }); } } ]); app.controller('home', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h', function($scope, $timeout, $http, $rootScope, $filter, h) { //if ($rootScope.user.firstrun) { if ($rootScope.user.firstrun) { $scope.fnModal('home/modal.firstrun'); } $scope.fnCloseFirstRun = function() { $http.get('/rest/user/firstrun.set'); $rootScope.user.firstrun = false; $scope.fnCloseModal(); } $scope.pagecharts = {}; $scope.curtemplate = {}; $scope.colors = h.colors(); $scope.page = { 'widgets': [{ 'type': 'analytics_timeline', 'metrics': ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll', 'uniquePageviews', 'avgTimeOnPage', 'entrances', 'exitRate', 'pageValue', 'transactions', 'uniquePurchases', 'totalValue', 'revenuePerTransaction', 'itemQuantity', 'itemsPerPurchase'], 'metric': 'sessions', 'colspan': 6 }, { 'type': 'analytics_chart', 'dimensions': ['channelGrouping', 'keyword', 'source', 'country', 'userAgeBracket', 'userGender', 'socialNetwork', 'deviceCategory', 'adMatchedQuery', 'productName', 'productCategory', 'pagePath', 'landingPagePath', 'exitPagePath'], 'dimension': 'landingPagePath', 'charts': ['pie', 'bar', 'progress'], 'chart': 'bar', 'metrics': ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll', 'uniquePageviews', 'avgTimeOnPage', 'entrances', 'exitRate', 'pageValue', 'transactions', 'uniquePurchases', 'totalValue', 'revenuePerTransaction', 'itemQuantity', 'itemsPerPurchase'], 'metric': 'sessions', 'colspan': 6 }, { 'type': 'analytics4_timeline', 'class': 'mt-4', 'metrics': ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'], 'metric': 'sessions', 'colspan': 6 }, { 'type': 'searchconsole_timeline', 'class': 'mt-4', 'metrics': ['clicks', 'ctr', 'position', 'impressions'], 'metric': 'clicks', 'colspan': 6 }, { 'type': 'searchconsole_chart', 'dimensions': ['query', 'page', 'country', 'device'], 'dimension': 'query', 'charts': ['pie', 'bar', 'progress'], 'chart': 'bar', 'metrics': ['clicks', 'ctr', 'position', 'impressions'], 'metric': 'clicks', 'colspan': 6 }, { 'type': 'searchconsole_keywords', 'colspan': 6 }, { 'type': 'googleads_timeline', 'class': 'mt-4', 'metrics': ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas'], 'metric': 'Clicks', 'colspan': 6 }, { 'type': 'googleads_performance_chart', 'dimensions': ['CampaignName', 'AdGroupName', 'Query'], 'dimension': 'CampaignName', 'charts': ['pie', 'bar', 'progress'], 'chart': 'bar', 'metrics': ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas'], 'metric': 'Clicks', 'colspan': 6 }, { 'type': 'googleads_conversion_chart', 'dimensions': ['ConversionTypeName'], 'dimension': 'ConversionTypeName', 'charts': ['pie', 'bar', 'progress'], 'chart': 'bar', 'metrics': ['Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue'], 'metric': 'Conversions', 'colspan': 6 }, { 'type': 'facebookinsights_timeline', 'class': 'mt-4', 'metrics': ['page_fans_total', 'page_impressions', 'engagements'], 'metric': 'page_fans_total', 'colspan': 6 }, { 'type': 'facebookads_timeline', 'metrics': ['clicks', 'impressions', 'cpc', 'cpm', 'spend', 'ctr'], 'metric': 'clicks', 'colspan': 6 }, { 'type': 'ranktracer', 'class': 'mt-4', 'colspan': 6 }, { 'type': 'onpage_seo', 'colspan': 12 }, { 'type': 'onpage_changes', 'colspan': 6 }, { 'type': 'onpage_changes_donut', 'colspan': 6 }], 'widths': [ { 'colspan': 3, 'width': '25%' }, { 'colspan': 4, 'width': '33%' }, { 'colspan': 6, 'width': '50%' }, { 'colspan': 8, 'width': '66%' }, { 'colspan': 9, 'width': '75%' }, { 'colspan': 12, 'width': '100%' }, ] } $scope.fnPctChange = function(o, n) { if (n == 0) { return '0%'; } var pct = ((n - o) / o) * 100; var npct = $filter('number')(pct, 2); if (pct < 0) { return '' + npct + '%'; } return '+ ' + npct + '%'; } $scope.do = function(obj, method, param) { if (obj == 'fnWidgets') { fnWidgets[method](param); } else if (obj == 'fnTemplates') { fnTemplates[method](param); } } var fnTemplates = { list: function() { $http.get('/rest/home/template.list', { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { $scope.templates = res.data; }); }, use: function(widgets) { $scope.widgets = widgets; fnWidgets.save(); $scope.fnCloseModal(); }, create: function() { var cleanwidgets = angular.copy($scope.widgets).map(function(c) { delete c.widget; return c; }) $scope.curtemplate.widgets = cleanwidgets; $http.post('/rest/home/template.save', { websiteid: h.siteId(), 'template': $scope.curtemplate }).then(function successCallback(res) { $scope.fnCloseModal(); }); }, save: function(template) { var cleanwidgets = angular.copy($scope.widgets).map(function(c) { delete c.widget; return c; }) template.widgets = cleanwidgets; template.name = ($scope.curtemplate.name) ? $scope.curtemplate.name : template.name; template.description = ($scope.curtemplate.description) ? $scope.curtemplate.description : template.description; $http.post('/rest/home/template.save', { websiteid: h.siteId(), 'template': template }).then(function successCallback(res) { $scope.fnCloseModal(); }); }, delete: function(template) { $http.post('/rest/home/template.delete', template).then(function successCallback(res) { $scope.fnCloseModal(); }); }, } var fnWidgets = { 'add': function(widget) { $http.post('/rest/home/widget.add', angular.extend({ websiteid: h.siteId() }, widget)).then(function successCallback(res) { $scope.fnCloseModal(); fnWidgets.list(); $scope.page.edit = false; }); }, 'save': function() { $http.post('/rest/home/widgets.save', angular.extend({ websiteid: h.siteId() }, { 'widgets': $scope.widgets })).then(function successCallback(res) { $scope.fnCloseModal(); fnWidgets.list(); $scope.page.edit = false; }); }, 'delete': function(widget) { angular.forEach($scope.widgets, function(v, k) { if (v.k == widget.k) { $scope.widgets.splice(k, 1); fnWidgets.save(); } }) }, 'reorder': function(o) { o.widget.order = o.widget.order - 0.1; angular.forEach($filter('orderBy')($scope.widgets, 'order', false), function(v, k) { v.order = k + 1; }); }, 'pre_add': function() { fnTemplates.list(); $scope.fnModal('home/modal.widgets'); }, 'pre_edit': function() { $scope.page.edit = true; }, 'list': function() { $http.get('/rest/home/widgets.list', { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { if (res.data.length == 0) { res.data = [ { "type": "onpage_seo", "metric": null, 'colspan': 12, 'order': 1, 'k': 'k1' }, { "type": "analytics4_timeline", "metric": "sessions", 'colspan': 4, 'order': 2, 'k': 'k2' }, { "type": "onpage_changes", "metric": null, 'colspan': 4, 'order': 3, 'k': 'k3' }, { "type": "searchconsole_keywords", "metric": null, 'colspan': 4, 'order': 4, 'k': 'k4' }, { "type": "searchconsole_timeline", "metric": 'clicks', 'colspan': 6, 'order': 5, 'k': 'k5' }, { "type": "ranktracer", "metric": null, 'colspan': 6, 'order': 6, 'k': 'k6' }, ]; } $scope.widgets = res.data; angular.forEach($scope.widgets, function(v, k) { fnWidgetGenerator[v.type](v); }) }); } } fnWidgets.list(); var _charts = { init: function(type, dataset, dimension, metric, dateformat) { return _charts[type](dataset, dimension, metric, dateformat); }, progress: function(dataset, dimension, metric) { return $filter('orderBy')(dataset, metric, true).slice(0, 5); }, bar: function(dataset, dimension, metric) { dataset = $filter('orderBy')(dataset, metric, true).slice(0, 8); //inject color attribute with value if (typeof dataset != undefined) { for (var i = 0; i < dataset.length; i++) { dataset[i].color = $scope.colors[i]; } } return { data: dataset.slice(0, 6), type: 'serial', categoryField: dimension, rotate: false, legend: { enabled: false }, categoryAxis: { gridPosition: "start", parseDates: false, labelRotation: 0, gridThickness: 0, labelFunction: function(value, valueText, axis) { return (value.length > 19) ? value.substr(0, 17) + '...' : value }, }, valueAxes: [{ position: "left", axisAlpha: 0, labelsEnabled: true, dashLength: 4, color: '#dedede', }], graphs: [{ fillColorsField: "color", balloonText: "[[category]]: [[value]]", type: "column", columnWidth: 0.40, title: "Zoekwoord waarde", valueField: metric, fillAlphas: 1, lineColor: '#009688', autoColor: true, }], } }, pie: function(dataset, dimension, metric) { dataset = $filter('orderBy')(dataset, metric, true).slice(0, 12); return { data: dataset.slice(0, 9), type: 'pie', categoryField: dimension, "precision": 0, "decimalSeparator": ",", "thousandsSeparator": ".", legend: { enabled: false, position: 'right', autoMargins: false, marginRight: 100, }, titleField: dimension, valueField: metric, labelRadius: 5, radius: '42%', innerRadius: '60%', labelText: '[[title]]', } }, timeline(dataset, dimension, metric, dateformat) { return { data: dataset, type: 'serial', categoryField: dimension, rotate: false, dataDateFormat: dateformat, categoryAxis: { gridPosition: "start", parseDates: true, gridThickness: 0 }, valueAxes: [{ position: "left", axisAlpha: 0, labelsEnabled: true, dashLength: 4, color: '#dedede', }], graphs: [{ 'balloonText': "Amount
[[value]]", "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0.3, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, "title": "Expenses", "valueField": metric, 'lineColor': fnWidgetGenerator.color() }], } } } var fnWidgetGenerator = { i: -1, 'color': function(i) { var colors = h.colors(); fnWidgetGenerator.i += 1; return colors[fnWidgetGenerator.i]; }, 'analytics_timeline': function(widget) { $http.get('/rest/analytics/v4', { params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), } }).then(function successCallback(res) { widget.widget = _charts.init('timeline', res.data.data, 'ga:date', widget.metric, 'YYYYMMDD') widget.widget.action = res.data.action; }); }, 'analytics4_timeline': function(widget) { $http.get('/rest/analytics4/report', { params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), } }).then(function successCallback(res) { widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYYMMDD') widget.widget.action = res.data.action; }); }, 'analytics_chart': function(widget) { $http.get('/rest/analytics/v4', { params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId() } }).then(function successCallback(res) { widget.widget = _charts.init(widget.chart, res.data.data, 'ga:' + widget.dimension, widget.metric) widget.widget.action = res.data.action; }); }, 'googleads_timeline': function(widget) { $http.get('/rest/googlexads/report', { params: { 'dimension': 'Date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'ACCOUNT_PERFORMANCE_REPORT' } }).then(function successCallback(res) { widget.widget = _charts.init('timeline', res.data.data, 'Date', widget.metric, 'YYYY-MM-DD') widget.widget.action = res.data.action; }); }, 'googleads_performance_chart': function(widget) { var report = { 'CampaignName': 'CAMPAIGN_PERFORMANCE_REPORT', 'AdGroupName': 'ADGROUP_PERFORMANCE_REPORT', 'Query': 'SEARCH_QUERY_PERFORMANCE_REPORT' }; $http.get('/rest/googlexads/report', { params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': report[widget.dimension] } }).then(function successCallback(res) { widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric) widget.widget.action = res.data.action; }); }, 'googleads_conversion_chart': function(widget) { $http.get('/rest/googlexads/report', { params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'ACCOUNT_PERFORMANCE_REPORT' } }).then(function successCallback(res) { widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric) widget.widget.action = res.data.action; }); }, 'facebookinsights_timeline': function(widget) { $http.get('/rest/facebookinsights/report', { params: { 'dimension': 'date', 'end': 'TODAY', 'start': '30DAYSAGO', websiteid: h.siteId(), 'endpoint': 'insights', 'report': 'timeline' } }).then(function successCallback(res) { if (widget.metric == 'engagements') { var data = res.data.sets[widget.metric].data.reduce(function(acc, cur) { if (cur.type == 'engagements') { acc.push({ 'change': cur.value, 'date': cur.date }); } return acc; }, []); } else { var data = res.data.sets[widget.metric].data } widget.widget = _charts.init('timeline', data, 'date', 'change', 'YYYY-MM-DD') widget.widget.action = res.data.action; }); }, 'facebookads_timeline': function(widget) { $http.get('/rest/facebookads/report', { params: { 'dimension': 'date', 'end': 'TODAY', 'start': '30DAYSAGO', websiteid: h.siteId(), 'level': 'account', 'endpoint': 'insights', 'metrics': widget.metric } }).then(function successCallback(res) { widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYY-MM-DD') widget.widget.action = res.data.action; }); }, 'onpage_changes': function(widget) { $http.get('/rest/onpage/rules', { 'params': { 'lang': $scope.user.site.locale.lang } }).then(function successCallback(res) { $scope.onpage = res.data; $http.get('/rest/onpage/changes', { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { widget.widget = res.data.data; }); }); }, 'onpage_changes_donut': function(widget) { $http.get('/rest/onpage/changes', { 'params': { websiteid: h.siteId() } }).then(function successCallback(res) { var stats = [{ 'label': 'change', 'value': 0, 'color': '#808080' }, { 'label': 'done', 'value': 0, 'color': '#4caf50' }, { 'label': 'issue', 'value': 0, 'color': '#ff9800' }]; for (var i in res.data.data) { if (res.data.data[i].r === true) { stats[1].value += 1; } else if (res.data.data[i].r === false) { stats[2].value += 1; } else { stats[0].value += 1; } } widget.widget = { data: stats, type: 'pie', marginLeft: 0, marginRight: 0, marginTop: 10, categoryField: 'label', "precision": 0, "decimalSeparator": ",", "thousandsSeparator": ".", legend: { enabled: false, position: 'right', autoMargins: false, marginRight: 100, }, titleField: 'label', valueField: 'value', "colorField": "color", labelRadius: 5, radius: '42%', innerRadius: '60%', labelText: '[[label]]', } }); }, 'onpage_seo': function(widget) { $http.get('/rest/onpage/list', { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { widget.widget = res.data; widget.widget.avg = { 'all': 0, 'technical': 0, 'content': 0, 'mobile': 0, 'indexability': 0 } if(widget.widget.history){ var l = widget.widget.history.length; angular.forEach(widget.widget.history, function(value, key) { widget.widget.avg['all'] += value.all / l widget.widget.avg['technical'] += value.technical / l widget.widget.avg['content'] += value.content / l widget.widget.avg['mobile'] += value.mobile / l widget.widget.avg['indexability'] += value.indexability / l }); } }); }, 'ranktracer': function(widget) { $http.get('/rest/rank-tracker/list', { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { for (var i in res.data) { res.data[i].summary.google.pos = res.data[i].summary.google.pos || 100 res.data[i].summary.googlemobile.pos = res.data[i].summary.googlemobile.pos || 100 res.data[i].health = 100 - ((res.data[i].summary.google.worst - res.data[i].summary.google.pos + .5) / (res.data[i].summary.google.worst - res.data[i].summary.google.best)) * 100; } widget.widget = res.data; }); }, 'searchconsole_keywords': function(widget) { $http.get('/rest/searchconsole/report', { params: { 'dimension': 'query', 'end': 'TODAY', 'metrics': 'clicks,ctr,position,impressions', 'start': '30DAYSAGO', 'report': 'searchAnalytics', websiteid: h.siteId(), } }).then(function successCallback(res) { widget.widget = res.data; }); }, 'searchconsole_chart': function(widget) { $http.get('/rest/searchconsole/report', { params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), } }).then(function successCallback(res) { widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric); widget.widget.action = res.data.action; }); }, 'searchconsole_timeline': function(widget) { $http.get('/rest/searchconsole/report', { params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'searchAnalytics' } }).then(function successCallback(res) { widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYY-MM-DD') widget.widget.action = res.data.action; }); }, }; } ]); app.controller('help', ['$scope', '$timeout', '$http', '$rootScope', 'h', function($scope, $timeout, $http, $rootScope, h) { $http.get('https://www.marketingtracer.com/help/listjson', { params: { lang: $rootScope.user.site.locale.lang, } }).then(function successCallback(res) { $scope.topics = res.data; }); $scope.getText = function(_id, sub_id, subtopic) { $http.get('https://www.marketingtracer.com/help/subtopicjson', { params: { lang: $rootScope.user.site.locale.lang, _id: _id, sub_id: sub_id, } }).then(function successCallback(res) { subtopic.html = res.data; }); } var users = { userList: function() { $http.get('/rest/user/reseller.site.list', { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { $scope.users = res.data; }); }, matchUser: function(UserId) { for (var i in $scope.users) { if ($scope.users[i]._id.$oid == UserId) { return $scope.users[i].name; } } return ''; } } } ]); app.controller('ranktracker', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h', function($scope, $timeout, $http, $rootScope, $filter, h) { $scope.rankings = []; $scope.page = { bFilterStar: false, label: '', lgchart: '', labels: {}, filter: {}, sortType: 'q', collapse: {}, chartlg: false, fnChartLg: function(c) { this.chartlg = (this.chartlg == c) ? false : c; }, sortReverse: false, fnSort: function(s) { if ($scope.page.sortType == s) { $scope.page.sortReverse = !$scope.page.sortReverse; } else { $scope.page.sortReverse = false; } $scope.page.sortType = s; }, provider: 'google' } $scope.fnCustomDate = { 'init': function() { var d = new Date() d.setMonth(d.getMonth() - 1); $scope.customdate = { 'start': d, 'end': new Date(), 'show': false } }, 'set': function() { $scope.customdate.show = false; $rootScope.reportdates.start = Math.round($scope.customdate.start.getTime() / 1000) $rootScope.reportdates.end = Math.round($scope.customdate.end.getTime() / 1000) $rootScope.reportdates.description = 'Custom'; $scope.getKeywords(); } } $scope.dateoptions = [ { start: false, end: false, description: 'All times' }, { start: 'TODAY', end: 'TODAY', description: 'Today' }, { start: 'YESTYERDAY', end: 'YESTYERDAY', description: 'Yesterday' }, { start: '7DAYSAGO', end: 'TODAY', description: 'Past 7 days' }, { start: '14DAYSAGO', end: 'TODAY', description: 'Past 14 days' }, { start: '30DAYSAGO', end: 'TODAY', description: 'Past 30 days' }, { start: '1YEARAGO', end: 'TODAY', description: 'Past year' }, { start: 'THISMONTH', end: 'TODAY', description: 'This month' }, { start: 'LASTMONTH', end: 'TODAY', description: 'Previous month' }, ] if (!$rootScope.reportdates) { $rootScope.reportdates = { 'start': false, 'end': false, 'description': 'All time' }; } $scope.fnDateSelection = function(reportdates) { $rootScope.reportdates.start = reportdates.start; $rootScope.reportdates.end = reportdates.end; $rootScope.reportdates.description = reportdates.description; $scope.getKeywords(); $scope.getVisibility(); } $scope.do = function(obj, method, param) { if (obj == 'fnSingle') { fnSingle[method](param); } else { fnMultiple[method](param); } } var fnSingle = { getParams: function(ranking) { return { 'websiteid': h.siteId(), 'ids': [ranking._id.$oid], } }, pre_options: function(ranking) { ranking.pre_options = !ranking.pre_options }, options: function(ranking) { $http.post("/rest/rank-tracker/edit", angular.extend({ 'summary.google.start': ranking.summary.google.start, 'summary.googlemobile.start': ranking.summary.googlemobile.start, 'meta.label': ranking.meta.label, 'url': ranking.url, 'fields': ['summary.google.start', 'summary.googlemobile.start', 'meta.label','url'] }, fnSingle.getParams(ranking))).then(function successCallback(res) { $scope.getKeywords(); }) }, delete: function(ranking) { $http.post("/rest/rank-tracker/delete", fnSingle.getParams(ranking)).then(function successCallback(res) { $scope.getKeywords(); }) }, star: function(ranking) { $http.post("/rest/rank-tracker/edit", angular.extend({ 'meta.star': !ranking.meta.star, fields: ['meta.star'] }, fnSingle.getParams(ranking))).then(function successCallback(res) { $scope.getKeywords(); }) }, } var fnMultiple = { getParams: function(ranking) { var ids = []; for (var i in $scope.rankings) { if ($scope.rankings[i].checked) { ids.push($scope.rankings[i]._id.$oid) } } return { 'websiteid': h.siteId(), 'ids': ids, } }, multioptions: function() { $scope.page.multioptions = false; for (var i in $scope.rankings) { if ($scope.rankings[i].checked) { $scope.page.multioptions = true; break } } }, check: function(ranking) { ranking.checked = !ranking.checked; fnMultiple.multioptions(); }, checkall: function(label) { $scope.page.labels[label] = !$scope.page.labels[label]; for (var i in $scope.rankings) { if ($scope.rankings[i].meta.label == label) { $scope.rankings[i].checked = $scope.page.labels[label]; } } fnMultiple.multioptions(); }, options: function(ranking) { $http.post("/rest/rank-tracker/edit", angular.extend({ 'meta.label': $scope.page.label, 'fields': ['meta.label'] }, fnMultiple.getParams(ranking))).then(function successCallback(res) { $scope.getKeywords(); }) }, delete: function(ranking) { $http.post("/rest/rank-tracker/delete", fnMultiple.getParams(ranking)).then(function successCallback(res) { $scope.getKeywords(); }) }, resetvolume: function(ranking) { $http.post("/rest/rank-tracker/resetvolume", fnMultiple.getParams(ranking)).then(function successCallback(res) { $scope.getKeywords(); }) }, export: function(ranking) { $http.post("/rest/rank-tracker/export", fnMultiple.getParams(ranking)).then(function successCallback(res) { var element = document.createElement('a'); element.setAttribute('href', 'data:text/html;,' + encodeURIComponent(res.data.csv)); element.setAttribute('download', 'export.csv'); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); }) }, exportxls: function(ranking) { $http.post("/rest/rank-tracker/exportxls", fnMultiple.getParams(ranking)).then(function successCallback(res) { var element = document.createElement('a'); element.setAttribute('href', 'data:text/html;,' + encodeURIComponent(res.data.csv)); element.setAttribute('download', 'export.xls'); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); }) }, } // ranking grafiek'heschiedenis $scope.fnRankingHistory = function(ranking, provider) { if (ranking.active && $scope.page.provider == provider) { ranking.active = false; return; } $scope.page.provider = provider; for (var x in $scope.rankings) { $scope.rankings[x].active = false; } ranking.active = true; $http.get("/rest/rank-tracker/history", { params: { websiteid: h.siteId(), ranking_id: ranking._id.$oid, provider: $scope.page.provider, start: $rootScope.reportdates.start, end: $rootScope.reportdates.end } }).then(function successCallback(res) { var data = res.data; var graphs = []; var _d = {}; var d = []; for (var i in data) { for (var y in data[i].data) { _d[data[i].data[y].date] = _d[data[i].data[y].date] || { 'date': data[i].data[y].date }; _d[data[i].data[y].date][i] = data[i].data[y].pos; } graphs.push({ balloonText: data[i].url + "
position: [[value]]", "title": data[i].url, "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, "valueField": i, "connect": false, }) } for (var i in _d) { d.push(_d[i]); } ranking.chart = { data: d, type: 'serial', theme: 'light', marginLeft: 0, marginRight: 0, marginTop: 10, categoryField: 'date', rotate: false, pathToImages: 'vendor/amchart/images/', dataDateFormat: 'YYYYMMDD', legend: { position: "bottom", enabled: true, "useGraphSettings": true, }, categoryAxis: { gridPosition: "start", parseDates: true, labelRotation: 45 }, valueAxes: [{ reversed: true, position: "left", axisAlpha: 0, labelsEnabled: true, minimum: 1, }], graphs: graphs, } }); } // haal alle sleutelwoorden op $scope.getKeywords = function(a) { // all active plans $scope.urls = {} var startDate = ($scope.custominit) ? $scope.custominit.start : $rootScope.reportdates.start; $scope.page.bFilterStar = ($scope.custominit) ? $scope.custominit.bFilterStar : $scope.page.bFilterStar; if($scope.page.bFilterStar == true){ $scope.page.filter.meta = {star:true}; } $http.get('/rest/rank-tracker/list', { params: { websiteid: h.siteId(), start: startDate, end: $rootScope.reportdates.end } }).then(function successCallback(res) { $scope.page.rankinglength = res.data.length; if ($scope.page.rankinglength === 0) { $scope.fnModal('rank-tracker/modal.addkeyword'); } $scope.change = { 'nverlies': 0, 'nwinst': 0, 'nsame': 0, 'verlies': 0, 'winst': 0, 'totaal': 0, 'n': 0 }; $scope.pie = { top3: 0, top10: 0, top100: 0, overig: 0 } $scope._rankings = angular.copy(res.data); //$scope.rankings = res.data; $scope.sortranking(); }); } $scope.switchstar = function(){ if($scope.page.filter.meta){ delete $scope.page.filter.meta; } else { $scope.page.filter.meta = {star:true}; } $scope.sortranking(); } $scope.sortranking = function(){ $scope.rankings = $filter('filter')($scope._rankings, $scope.page.filter); if ($scope.rankings.length > 0) { for (var i in $scope.rankings) { if ($scope.rankings[i].active) { var active = i; } } } var sorted = {}; // some stats var totalenhancements = {}; for (var i in $scope.rankings) { var ranking = $scope.rankings[i]; ranking.meta.label = ranking.meta.label || '--'; if (ranking?.url && ranking.url.indexOf('http') != 0) { ranking.url = 'https://' + ranking.url; } ranking.summary.google.pos = ranking.summary.google.pos || 100 ranking.summary.googlemobile.pos = ranking.summary.googlemobile.pos || 100 if (active && i == active) { $scope.fnRankingHistory(ranking, $scope.page.provider); } // kan weg if (ranking.summary.google.pos < 4) { ++$scope.pie.top3; } else if (ranking.summary.google.pos < 11) { ++$scope.pie.top10; } else if (ranking.summary.google.pos < 100) { ++$scope.pie.top100; } else { ++$scope.pie.overig; } //health ranking.health = 100 - ((ranking.summary.google.worst - ranking.summary.google.pos + .5) / (ranking.summary.google.worst - ranking.summary.google.best)) * 100; if (ranking.health > 100) { ranking.health = 100; } sorted[ranking.meta.label] = sorted[ranking.meta.label] || []; sorted[ranking.meta.label].push(ranking); //change if (ranking.summary.google.start > ranking.summary.google.pos) { $scope.change.nwinst += 1; $scope.change.winst += ranking.summary.google.start - ranking.summary.google.pos; } else if (ranking.summary.google.start < ranking.summary.google.pos) { $scope.change.nverlies += 1; $scope.change.verlies += ranking.summary.google.pos - ranking.summary.google.start; } else { $scope.change.nsame += 1; } // enhancements var enhancements = {}; if (typeof ranking.summary.google.enhancements == 'object' && ranking.summary.google.enhancements != null) { if (typeof ranking.summary.google.enhancements.other == 'object') { ranking.summary.google.enhancements.other = ranking.summary.google.enhancements.other || {} ranking.summary.google.enhancements.other = Object.values(ranking.summary.google.enhancements.other); } if (typeof ranking.summary.google.enhancements.my == 'object') { ranking.summary.google.enhancements.my = ranking.summary.google.enhancements.my || {} ranking.summary.google.enhancements.my = Object.values(ranking.summary.google.enhancements.my); } ranking.summary.google.enhancements.other = ranking.summary.google.enhancements.other || []; ranking.summary.google.enhancements.my = ranking.summary.google.enhancements.my || []; ranking.summary.google.enhancements.other.forEach(function(v, k) { totalenhancements[v] = totalenhancements[v] || { 'v': v, 'my': 0, 'other': 0 }; totalenhancements[v].other += 1; enhancements[v] = enhancements[v] || { 'v': v, 'my': 0, 'other': 0 } enhancements[v].other += 1; }) ranking.summary.google.enhancements.my.forEach(function(v, k) { totalenhancements[v] = totalenhancements[v] || { 'v': v, 'my': 0, 'other': 0 }; totalenhancements[v].my += 1; enhancements[v] = enhancements[v] || { 'v': v, 'my': 0, 'other': 0 } enhancements[v].my += 1; }) } ranking.enhancements = Object.values(enhancements).sort(function(a, b) { return (a.v < b.v) ? -1 : 1 }); $scope.totalenhancements = Object.values(totalenhancements).sort(function(a, b) { return (a.v < b.v) ? -1 : 1 }); $scope.change.n += 1; $scope.change.totaal += ranking.summary.google.start - ranking.summary.google.pos; } $scope.sortedranking = sorted; } $scope.charts = {}; $scope.changes = {}; var chart = { small: { "type": 'serial', "categoryField": 'date', "dataDateFormat": 'YYYYMMDD', "autoMargins": false, "categoryAxis": { "parseDates": true, "gridAlpha": 0, "axisAlpha": 0, }, "valueAxes": [{ "gridAlpha": 0, "axisAlpha": 0, "color": '#FFFFFF', "stackType": "regular", }], }, large: { "type": 'serial', "categoryField": 'date', "dataDateFormat": 'YYYYMMDD', "autoMargins": true, "categoryAxis": { "gridPosition": "start", "parseDates": true, "gridThickness": 0 }, "valueAxes": [{ "position": "left", "axisAlpha": 0, "labelsEnabled": true, "dashLength": 4, "color": '#dedede', "stackType": "regular" }], }, visibility: function(data, type) { $scope.charts.visibility = angular.extend({}, chart[type], { data: data, graphs: [{ balloonText: "Visibility: [[value]]%", "fillAlphas": 0, "lineAlpha": 1, "bulletAlpha": 0.7, "valueField": 'visibility', "lineColor": h.colors()[1], }], }) $scope.charts.visibilitylg = angular.extend({}, chart['large'], { data: data, graphs: [{ balloonText: "Visibility: [[value]]%", "lineAlpha": 1, "valueField": 'visibility', "lineColor": h.colors()[1], "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, }], }) $scope.changes.visibility = { 'cur': data[data.length - 1].visibility, 'start': data[0].visibility, 'dif': data[data.length - 1].visibility - data[0].visibility } }, avgpos: function(data, type) { var _data = data.reduce(function(acc, cur) { if (cur.avg) { acc.push(cur); } return acc; }, []); if (_data.length == 1) { _data.unshift({ "date": "20191031", "avg": 0 }) } $scope.charts.avgpos = angular.extend({}, chart[type], { data: _data, graphs: [{ balloonText: "Avg position: [[value]]", "lineAlpha": 1, "valueField": 'avg', "lineColor": h.colors()[3], }], "valueAxes": [{ "gridAlpha": 0, "axisAlpha": 0, "color": '#FFFFFF', "stackType": "regular", "reversed": true, }], }) $scope.charts.avgposlg = angular.extend({}, chart['large'], { data: _data, graphs: [{ balloonText: "Avg position: [[value]]", "valueField": 'avg', "lineColor": h.colors()[3], "lineAlpha": 1, "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, }], "valueAxes": [{ "gridAlpha": 0, "axisAlpha": 0, "color": '#FFFFFF', "stackType": "regular", "reversed": true, }], }) $scope.changes.avgpos = { 'cur': _data[_data.length - 1].avg, 'start': _data[0].avg, 'dif': (_data[_data.length - 1].avg - _data[0].avg) * -1 } }, enhancement: function(data, type) { var _data = data.reduce(function(acc, cur) { if (cur.my_enh || cur.other_enh) { acc.push(cur); } return acc; }, []); if (_data.length == 1) { _data.unshift({ "date": "20191031", "my_enh": 0, 'other_enh': 0 }) } $scope.charts.enhancement = angular.extend({}, chart[type], { data: _data, graphs: [{ balloonText: "My enhancements: [[value]]", "fillAlphas": 0.6, "lineAlpha": 1, "valueField": 'my_enh', "lineColor": h.colors()[4], }, { balloonText: "Total enhancements: [[value]]", "fillAlphas": 0.6, "lineAlpha": 1, "valueField": 'other_enh', "lineColor": '#DDDDDD', }], }) $scope.charts.enhancementlg = angular.extend({}, chart['large'], { data: _data, graphs: [{ balloonText: "My enhancements: [[value]]", "bullet": "round", "lineAlpha": 1, "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0.6, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, "valueField": 'my_enh', "lineColor": h.colors()[4], }, { balloonText: "Total enhancements: [[value]]", "bullet": "round", "lineAlpha": 1, "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0.6, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, "valueField": 'other_enh', "lineColor": '#DDDDDD', }], }) $scope.changes.enhancement = { 'cur': _data[_data.length - 1]?.my_enh, 'start': _data[0]?.my_enh, 'dif': _data[_data.length - 1]?.my_enh - _data[0]?.my_enh } }, top: function(data, type) { var _data = data.reduce(function(acc, cur) { if (cur.top3 || cur.top10 || cur.top50 || cur.top100 || cur.norank) { acc.push(cur); } return acc; }, []); if (_data.length == 1) { _data.unshift({ "date": "20191031", "top3": 0, "top10": 0, "top50": 0, "top100": 0, "norank": 0 }) } $scope.charts.toplg = angular.extend({}, chart['large'], { data: _data, graphs: [ { balloonText: "Not ranked: [[value]]", "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0.6, "lineThickness": 2, "bulletSize": 7, "lineAlpha": 0.4, "valueField": 'norank', "lineColor": '#DDDDDD', }, { balloonText: "Top100: [[value]]", "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0.25, "lineThickness": 2, "bulletSize": 7, "lineAlpha": 0.4, "valueField": 'top100', "lineColor": h.colors()[2], }, { balloonText: "Top50: [[value]]", "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0.5, "lineThickness": 2, "bulletSize": 7, "lineAlpha": 0.4, "valueField": 'top50', "lineColor": h.colors()[2], }, { balloonText: "Top10: [[value]]", "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0.75, "lineThickness": 2, "bulletSize": 7, "lineAlpha": 0.4, "valueField": 'top10', "lineColor": h.colors()[2], }, { balloonText: "Top3: [[value]]", "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 1, "lineThickness": 2, "bulletSize": 7, "lineAlpha": 0.4, "valueField": 'top3', "lineColor": h.colors()[2], }, { balloonText: "Top1: [[value]]", "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 1, "lineThickness": 2, "bulletSize": 7, "lineAlpha": 0.4, "valueField": 'top1', "lineColor": h.colors()[2], }, ], }) $scope.charts.top = angular.extend({}, chart[type], { data: _data, graphs: [ { balloonText: "Not ranked: [[value]]", "fillAlphas": 0.6, "lineAlpha": .6, "valueField": 'norank', "lineColor": '#DDDDDD', }, { balloonText: "Top100: [[value]]", "fillAlphas": 0.25, "lineAlpha": .25, "valueField": 'top100', "lineColor": h.colors()[2], }, { balloonText: "Top50: [[value]]", "fillAlphas": 0.45, "lineAlpha": 0.45, "valueField": 'top50', "lineColor": h.colors()[2], }, { balloonText: "Top10: [[value]]", "fillAlphas": 0.65, "lineAlpha": 0.65, "valueField": 'top10', "lineColor": h.colors()[2], }, { balloonText: "Top3: [[value]]", "fillAlphas": 0.85, "lineAlpha": 0.85, "valueField": 'top3', "lineColor": h.colors()[2], }, { balloonText: "Top1: [[value]]", "fillAlphas": 1, "lineAlpha": 1, "valueField": 'top1', "lineColor": h.colors()[2], }, ], }) $scope.changes.top = { 'cur': _data[_data.length - 1], 'start': _data[0], 'dif': { 'top1': _data[_data.length - 1].top1 - _data[0].top1 || 0, 'top3': _data[_data.length - 1].top3 - _data[0].top3 || 0, 'top10': _data[_data.length - 1].top10 - _data[0].top10 || 0, 'top50': _data[_data.length - 1].top50 - _data[0].top50 || 0, 'top100': _data[_data.length - 1].top100 - _data[0].top100 || 0, 'norank': _data[_data.length - 1].norank - _data[0].norank || 0, } } }, } // haal alle sleutelwoorden op $scope.getVisibility = function(a) { $http.get("/rest/rank-tracker/visibility", { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { chart.avgpos(res.data, 'small'); chart.visibility(res.data, 'small'); chart.enhancement(res.data, 'small'); chart.top(res.data, 'small'); }); } $scope.fnAddKeywords = function() { $http.post('/rest/rank-tracker/add', { keywords: $scope.page.addkeywords, websiteid: h.siteId() }).then(function successCallback(res) { $scope.getKeywords(); $scope.fnCloseModal(); $scope.page.addkeywords = ''; }); } $scope.getKeywords(); $scope.getVisibility(); } ]); app.controller('ranktrackerinsights', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h', function($scope, $timeout, $http, $rootScope, $filter, h) { $scope.rankings = []; if($scope.custominit){ $scope.page = {'timeframe': '31d'}; $scope.mds = [ { 'title': '31-day mean - position improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dc', 'lengthindex': '31dl', 'comp': 'gt' }, { 'title': '31-day mean - position loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dc', 'lengthindex': '31dw', 'comp': 'lt' }, ]; } else { $scope.page = {'timeframe': '3d'}; $scope.mds = [ { 'title': '3-day mean - position improvement', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': '-median.s3dc', 'lengthindex': '3dw', 'comp': 'gt' }, { 'title': '3-day mean - traffic improvement', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': '-median.s3dvol', 'lengthindex': '3dw', 'comp': 'gt' }, { 'title': '3-day mean - position loss', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': 'median.s3dc', 'lengthindex': '3dl', 'comp': 'lt' }, { 'title': '3-day mean - traffic loss', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': 'median.s3dvol', 'lengthindex': '3dl', 'comp': 'lt' }, { 'title': '7-day mean - position improvement', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': '-median.s7dc', 'lengthindex': '7dw', 'comp': 'gt' }, { 'title': '7-day mean - traffic improvement', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': '-median.s7dvol', 'lengthindex': '7dw', 'comp': 'gt' }, { 'title': '7-day mean - position loss', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': 'median.s7dc', 'lengthindex': '7dl', 'comp': 'lt' }, { 'title': '7-day mean - traffic loss', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': 'median.s7dvol', 'lengthindex': '7dl', 'comp': 'lt' }, { 'title': '31-day mean - position improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dc', 'lengthindex': '31dl', 'comp': 'gt' }, { 'title': '31-day mean - traffic improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dvol', 'lengthindex': '31dl', 'comp': 'gt' }, { 'title': '31-day mean - position loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dc', 'lengthindex': '31dw', 'comp': 'lt' }, { 'title': '31-day mean - traffic loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dvol', 'lengthindex': '31dw', 'comp': 'lt' }, ]; } $scope.exists = function(prop, comp) { return function(item) { return item.median.hasOwnProperty(prop) && (comp == 'lt') ? item.median[prop] < 0 : item.median[prop] > 0 } } var competitors = { listinsights: function() { $http.get("/rest/rank-tracker/median", { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { $scope.insights = res.data; $scope.lengths = $scope.insights.reduce(function(acc, cur) { if (cur.median.s3dc > 0) { acc['3dw'] += 1; } else if (cur.median.s3dc < 0) { acc['3dl'] += 1; } if (cur.median.s7dc > 0) { acc['7dw'] += 1; } else if (cur.median.s7dc < 0) { acc['7dl'] += 1; } if (cur.median.s7dc > 0) { acc['31dw'] += 1; } else if (cur.median.s31dc < 0) { acc['31dl'] += 1; } return acc; }, { '3dl': 0, '3dw': 0, '7dl': 0, '7dw': 0, '31dl': 0, '31dw': 0 }) }); }, } competitors.listinsights(); // ranking grafiek'heschiedenis $scope.fnRankingHistory = function(ranking, provider) { if (ranking.active && $scope.page.provider == provider) { ranking.active = false; return; } $scope.page.provider = provider; for (var x in $scope.rankings) { $scope.rankings[x].active = false; } ranking.active = true; $http.get("/rest/rank-tracker/history", { params: { websiteid: h.siteId(), ranking_id: ranking._id.$oid, provider: 'google', } }).then(function successCallback(res) { var data = res.data; var graphs = []; var _d = {}; var d = []; for (var i in data) { for (var y in data[i].data) { _d[data[i].data[y].date] = _d[data[i].data[y].date] || { 'date': data[i].data[y].date }; _d[data[i].data[y].date][i] = data[i].data[y].pos; } graphs.push({ balloonText: data[i].url + "
position: [[value]]", "title": data[i].url, "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, "valueField": i, "connect": false, }) } for (var i in _d) { d.push(_d[i]); } ranking.chart = { data: d, type: 'serial', theme: 'light', marginLeft: 0, marginRight: 0, marginTop: 10, categoryField: 'date', rotate: false, pathToImages: 'vendor/amchart/images/', dataDateFormat: 'YYYYMMDD', legend: { position: "bottom", enabled: true, "useGraphSettings": true, }, categoryAxis: { gridPosition: "start", parseDates: true, labelRotation: 45 }, valueAxes: [{ reversed: true, position: "left", axisAlpha: 0, labelsEnabled: true, minimum: 1, }], graphs: graphs, } }); } // set competitors $scope.fnAddCompetitors = function() { $http.post('/rest/rank-tracker/competitors.edit', { competitors: $scope.competitors, websiteid: h.siteId() }).then(function successCallback(res) { competitors.listinsights(); competitors.listkeywords(); $scope.fnCloseModal(); }); } } ]); app.controller('ranktrackercompetitors', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h', function($scope, $timeout, $http, $rootScope, $filter, h) { $scope.rankings = []; $scope.blazak = {}; $scope.page = { label: '', labels: {}, table: { 'curpage': 0, 'itemsperpage': 14, 'offset': 0, 'filter': {}, 'order': { 'k': 'url', 'r': false }, 'fnOrder': function(k, b) { this.order.r = (k == this.order.k) ? !this.order.r : b; this.order.k = k; }, fnSetOffset: function() { this.offset = this.itemsperpage * (this.curpage - 1); }, fnFilterProperty: function() { var pages = angular.copy($rootScope._pages); $scope.pages = $filter('filter')(pages, $scope.page.table.filter); } }, date: 'alltime', dates: ['alltime', '4weeks', '4months', 'thismonth'], tab: 'my', provider: 'google' } $scope.do = function(obj, method, param) { if (obj == 'fnSingle') { fnSingle[method](param); } else { fnMultiple[method](param); } } var competitors = { listcompetitors: function() { $http.get("/rest/rank-tracker/competitors.list", { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { $scope.competitors = res.data; if ($scope.competitors.length === 0 && $rootScope.user.site.role < 6) { $scope.fnModal('rank-tracker/modal.editcompetitors'); } }); }, listkeywords: function() { if ($scope.rankings.length > 0) { for (var i in $scope.rankings) { if ($scope.rankings[i].active) { var active = i; } } } var sorted = {}; // all active plans $scope.urls = {} $http.get('/rest/rank-tracker/competitors.listkeywords', { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { $scope.page.rankinglength = res.data.length; $scope.rankings = res.data; // some stats for (var i in $scope.rankings) { var ranking = $scope.rankings[i]; ranking.summary.google.pos = ranking.summary.google.pos || 100 ranking.summary.googlemobile.pos = ranking.summary.googlemobile.pos || 100 sorted[ranking.meta.label] = sorted[ranking.meta.label] || []; sorted[ranking.meta.label].push(ranking); } $scope.sortedranking = sorted; }); } } competitors.listcompetitors(); competitors.listkeywords(); // ranking grafiek'heschiedenis $scope.fnRankingHistory = function(ranking, provider) { provider = 'google'; console.log(ranking); if (ranking.active && $scope.page.provider == provider) { ranking.active = false; return; } $scope.page.provider = provider; for (var x in $scope.rankings) { $scope.rankings[x].active = false; } ranking.active = true; $http.get("/rest/rank-tracker/competitors.history", { params: { websiteid: h.siteId(), ranking_id: ranking._id.$oid, provider: $scope.page.provider, } }).then(function successCallback(res) { var data = res.data; var graphs = []; var _d = {}; var d = []; for (var i in data) { console.log(data[i]); for (var y in data[i].data) { _d[data[i].data[y].date] = _d[data[i].data[y].date] || { 'date': data[i].data[y].date }; _d[data[i].data[y].date][i] = data[i].data[y].pos; } graphs.push({ balloonText: data[i].url + "
position: [[value]]", "title": data[i].url, "bullet": "round", "bulletBorderAlpha": 1, "bulletColor": "#FFFFFF", "useLineColorForBulletBorder": true, "fillAlphas": 0, "lineThickness": 2, "lineAlpha": 1, "bulletSize": 7, "valueField": i, "connect": false, }) } for (var i in _d) { d.push(_d[i]); } ranking.chart = { data: d, type: 'serial', theme: 'light', marginLeft: 0, marginRight: 0, marginTop: 10, fontFamily: 'Roboto', categoryField: 'date', rotate: false, pathToImages: 'vendor/amchart/images/', dataDateFormat: 'YYYYMMDD', legend: { position: "bottom", enabled: true, "useGraphSettings": true, }, categoryAxis: { gridPosition: "start", parseDates: true, labelRotation: 45 }, valueAxes: [{ reversed: true, position: "left", axisAlpha: 0, labelsEnabled: true, minimum: 1, }], graphs: graphs, } }); } // set competitors $scope.fnAddCompetitors = function() { $http.post('/rest/rank-tracker/competitors.edit', { competitors: $scope.competitors, websiteid: h.siteId() }).then(function successCallback(res) { competitors.listcompetitors(); competitors.listkeywords(); $scope.fnCloseModal(); }); } } ]); app.controller('linkbuildingassistant', ['$scope', '$http', '$rootScope', '$window', '$filter', 'h', function($scope, $http, $rootScope, $window, $filter, h) { $scope.page = { 'quickselect': {}, 'importtab': false, 'categories': [], 'tags': {}, 'dates': [], 'kdates': {}, 'newlink': { 'moz': { 'targetscope': 'page', 'n': '50' } }, 'multiplelinks': {}, 'filter': {}, table: { 'curpage': 0, 'itemsperpage': 100, 'offset': 0, fnSetOffset: function() { this.offset = this.itemsperpage * (this.curpage - 1); }, } } /* months*/ var thismonth = new Date().getMonth() + 3; for (var i = 0; i < 15; i++) { var date = new Date(new Date().getFullYear(), thismonth, 0); $scope.page.dates.push({ 'date': date }); $scope.page.kdates[date.toString()] = date; thismonth = thismonth - 1; } // do $scope.do = function(obj, method, param) { if (obj == 'fnSingle') { return fnSingle[method](param); } else if (obj == 'fnWizzard') { return fnWizzard[method](param); } else if (obj == 'fnTemplates') { return fnTemplates[method](param); } else { return fnMultiple[method](param); } } // link var fnLinks = { list: function() { $http.get("/rest/linkbuilding/link.list", { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { $scope.page.multioptions = false; $scope.page.checkall = false; for (var i in res.data) { var date = new Date(res.data[i].date * 1); res.data[i].monthstring = date.toLocaleString('default', { year: 'numeric', 'month': 'long' }) res.data[i].d = res.data[i].date*1; res.data[i].date = $scope.page.kdates[date.toString()]; if (res.data[i].my.tag) { $scope.page.tags[res.data[i].my.tag] = res.data[i].my.tag; } } res.data = $filter('orderBy')(res.data, 'd', true) $scope.links = res.data; }); }, } // categories var fnCategories = { list: function() { if ($scope.categories) { return; } $http.get('/rest/linkbuilding/manager.categories.list').then(function successCallback(res) { $scope.categories = res.data; }); } } // categories var fnTemplates = { list: function() { $http.get('/rest/linkbuilding/template.list', { params: { 'websiteid': h.siteId(), } }).then(function successCallback(res) { $scope.mailTemplates = res.data; }); }, 'get_mails_by_key': function(key) { for (var i in $scope.mailTemplates) { if ($scope.mailTemplates[i].key == key) { return $scope.mailTemplates[i].mails; } } } } //wizzard var fnWizzard = { 'moz-domain': function() { $http.post("/rest/linkbuilding/wizzard.moz.domain", angular.extend({ 'domain': $scope.page.mozdomain }, { websiteid: h.siteId() }) ).then(function successCallback(res) { fnLinks.list(); }); }, 'add_url': function() { $http.post("/rest/linkbuilding/link.add.url", angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) }) ).then(function successCallback(res) { $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } }; fnLinks.list(); }); }, 'add_bulk': function() { $http.post("/rest/linkbuilding/link.add.bulk", angular.extend({ 'my': $scope.page.newlink.my, 'bulk': $scope.page.newlink.bulk, 'allowduplicates': $scope.page.newlink.allowduplicates }, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) }) ).then(function successCallback(res) { $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } }; fnLinks.list(); }); }, 'add_search': function() { $http.post("/rest/linkbuilding/link.add.search", angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) }) ).then(function successCallback(res) { $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } }; fnLinks.list(); }); }, 'add_moz': function() { $http.post("/rest/linkbuilding/link.add.moz", angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) }) ).then(function successCallback(res) { $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } }; fnLinks.list(); }); }, 'list_google_alerts': function() { $http.get("/rest/linkbuilding/rss.list.google.alerts", { params: { websiteid: h.siteId(), } }).then(function successCallback(res) { $scope.page.google_alerts = res.data; }); }, 'add_google_alerts': function() { $http.post("/rest/linkbuilding/rss.add.google_alerts", angular.extend({}, { 'alert': $scope.page.newlink.google_alerts }, { websiteid: h.siteId() }) ).then(function successCallback(res) { $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } }; $scope.page.importtab = false; fnLinks.list(); }); }, 'remove_google_alert': function(alert) { $http.post("/rest/linkbuilding/rss.remove.google.alerts", angular.extend({}, { 'alert': alert }, { websiteid: h.siteId() }) ).then(function successCallback(res) { fnWizzard.list_google_alerts(); $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } }; }); }, } $scope.fnCopyText = function(text) { var body = angular.element($window.document.body); var textarea = angular.element('